<template>
  <div class="stream-markdown">
    <!-- 渲染区域：使用 v-html 展示实时转换的 HTML -->
    <div class="content" v-html="renderedHtml"></div>
    <!-- 加载状态：流式渲染时显示 -->
    <div v-if="isStreaming" class="typing-indicator"><span></span><span></span><span></span></div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, watch } from "vue";
import { marked } from "marked";
import hljs from "highlight.js";
import "highlight.js/styles/github-dark.css"; // 代码高亮样式

// 1. 接收外部传入的 Markdown 完整内容
const props = defineProps({
  content: {
    type: String,
    required: true,
    default: ""
  },
  // 流式速度：每段延迟时间（毫秒）
  speed: {
    type: Number,
    default: 300
  }
});

// 2. 核心状态管理
const rawSegments = ref([]); // 拆分后的 Markdown 片段数组
const displayedSegments = ref([]); // 已显示的片段数组
const isStreaming = ref(false); // 是否正在流式渲染
let intervalId = null; // 定时器ID（用于清理）

// 3. 拆分 Markdown 内容为片段
// 按“换行+空行”拆分（适用于段落、标题、代码块等块级元素）
const splitIntoSegments = (md) => {
  // 正则：按空行（至少一个换行）拆分，保留分隔符（确保结构正确）
  return md.split(/(\n\s*\n)/).filter((segment) => segment.trim() !== "");
};

// 4. 配置 marked 转换（支持代码高亮）
marked.setOptions({
  highlight: (code, lang) => {
    if (lang && hljs.getLanguage(lang)) {
      return hljs.highlight(code, { language: lang }).value;
    }
    return hljs.highlightAuto(code).value;
  },
  breaks: true, // 支持换行
  gfm: true // 支持 GitHub 风格的 Markdown
});

// 5. 实时转换已显示的片段为 HTML
const renderedHtml = computed(() => {
  const fullContent = displayedSegments.value.join("");
  return marked.parse(fullContent);
});

// 6. 流式渲染逻辑
const startStreaming = () => {
  if (rawSegments.value.length === 0) return;
  isStreaming.value = true;
  let index = 0;
  // 定时器：逐段添加片段
  // intervalId = setInterval(() => {
  displayedSegments.value.push(rawSegments.value[index]);
  index++;
  // 所有片段显示完毕，清理定时器
  if (index >= rawSegments.value.length) {
    isStreaming.value = false;
  }
  // }, props.speed);
};

// 7. 生命周期：初始化和清理
onMounted(() => {
  rawSegments.value = splitIntoSegments(props.content);
  startStreaming();
});
// watch(
//   () => props.content,
//   (newval, oldval) => {
//     rawSegments.value = splitIntoSegments(props.content);
//     startStreaming();
//   }
// );

onUnmounted(() => {
  // 组件销毁时清理定时器，避免内存泄漏
  if (intervalId) clearInterval(intervalId);
});
</script>

<style scoped>
.stream-markdown {
  line-height: 1.8;
  font-size: 16px;
}

/* 内容区域样式 */
.content {
  transition: opacity 0.3s ease;
}
/* 流式渲染时的淡入效果 */
.content.streaming {
  opacity: 0.95;
}

/* 代码块样式增强 */
.content pre {
  background: #2d2d2d;
  padding: 16px;
  border-radius: 6px;
  overflow-x: auto;
  margin: 12px 0;
}
.content code {
  font-family: "Fira Code", monospace;
  font-size: 14px;
}

/* 打字指示器（三个点动画） */
.typing-indicator {
  display: flex;
  gap: 4px;
  margin-top: 8px;
}
.typing-indicator span {
  width: 8px;
  height: 8px;
  background: #888;
  border-radius: 50%;
  animation: typing 1.4s infinite ease-in-out both;
}
.typing-indicator span:nth-child(1) {
  animation-delay: -0.32s;
}
.typing-indicator span:nth-child(2) {
  animation-delay: -0.16s;
}

@keyframes typing {
  0%,
  80%,
  100% {
    transform: scale(0);
  }
  40% {
    transform: scale(1);
  }
}
</style>
